<?php
require_once 'models/acl.inc';
require_once 'services/TPageService.inc';

class TMSSecurityPolicy extends TConfigurable implements IPolicyChecker {
	private $_access_;
	
	private $_initiated_ = false;
	
	public function __set($nm,$value){
		switch ($nm){
			case 'Access':{
				$this->_init_access();
				if (is_string($value))
					$value = TConvertions::ConvertToArray($value,array("\n",'=',','),array(false,true,false));
				if (is_array($value)){
					if (!is_array($this->_access_))
						$this->_access_ = array();
					foreach ($value as $key=>$val){
						$this->_access_[$key] = 0;
						foreach ($val as $v)
							$this->_access_[$key] = $this->_access_[$key] | (is_int($v)?$v:(defined('TMSRole::'.mb_strtoupper($v))?constant('TMSRole::'.mb_strtoupper($v)):0));
					}
				}
			}break;
			default:parent::__set($nm, $value);break;
		}
	}
	
	private function _init_access(){
		if (!$this->_initiated_){
			$this->_initiated_ = true;
			$fn = $this->Application()->PrivateDir().'/'.$this->Name().'.conf';
			if (file_exists($fn))
				$this->Access = file_get_contents($fn);
			$fn = $this->Application()->OverrideDir().'/'.$this->Name().'.conf';
			if (file_exists($fn))
				$this->Access = file_get_contents($fn);
		}
	}
	
/**
 * checks policy of security subject
 * @param ISecuritySubject $subject subject to check
 * @param TPolicy $policy policy to check
 */	
	public function CheckPolicy(ISecuritySubject $subject, TPolicy $policy){
		$this->_init_access();
		if (!isset($this->_access_[$policy->SecurityObject()->Soid()]))
			return true;
		if ($subject instanceof TMSUser){
			foreach ($subject->Cooperators() as $c)
				if ($this->CheckPolicy($c, $policy))
					return true;
		} else if ($subject instanceof TMSRole){
			if (isset($this->_access_[$policy->SecurityObject()->Soid()]) && $this->_access_[$policy->SecurityObject()->Soid()])
				return $this->_access_[$policy->SecurityObject()->Soid()] & $subject->Guid();
			else return true;
		}
		return false;
	}
/**
 * checks policy of several security subjects
 * @param array $subjects array of ISecuritySubject
 * @param TPolicy $policy policy to check
 */	
	public function CheckSubjectsPolicy(array $subjects, TPolicy $policy){
		foreach ($subjects as $s){
			if ($this->CheckPolicy($s, $policy))
				return true;
		}
		return false;
	}
/**
 * checks if any of specified policies are granted to security subjects over security objects
 * @param ISecuritySubject[] $subjects list of subjects
 * @param ISecurityObject[] $objects list of objects, if empty global policies are checked 
 * @param TPolicy[] $policies list of policies
 * @return boolean 
 */	
	public function CheckSubjectsObjectsPolicies(array $subjects, array $objects, array $policies){
		foreach ($policies as $p)
			if ($p instanceof TPagePolicy){
				foreach ($objects as $o)
					if ($o instanceof TPage) {
						if ($this->CheckSubjectsPolicy($subjects,new TPagePolicy(TPagePolicy::PAGE_ACCESS,$o)))
							return true;
					}
				break;
			}
		return false;
	}
}